package by.home.app;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

public class Tree implements Serializable{
    public TreeNode root;
    private static final Logger logger = Logger.getLogger(Tree.class);
    String treeString="";

    public Tree(){
        super();
        DOMConfigurator.configure("log4j.xml");
    }
    public Tree(UserData obj){
        DOMConfigurator.configure("log4j.xml");
        logger.info("Creating new Tree with root..");
        this.root = new TreeNode(obj);
        logger.info("Tree successfully created !");
    }

    public void addNode(UserData obj){
        logger.warn("Adding new node..");
        logger.warn("Checking root node..");
        if (root == null){
            root = new TreeNode(obj);
            logger.info("New root node created !");
        }
        else {
            logger.info("Root already exists !");
            TreeNode it = root;
            TreeNode newNode = new TreeNode(obj);
            logger.warn("Comparing root to the child nodes..");
            while (newNode.getParent() == null){
                if ((newNode.compareTo(it) == -1) && (it.getLeftChild() != null)){  //if newNode < it
                    it = it.getLeftChild();
                }
                else if((newNode.compareTo(it) == -1) && (it.getLeftChild() == null)){
                    newNode.addParent(it);
                    it.addLeftChild(newNode);
                }
                else if((newNode.compareTo(it) == 1) && (it.getRightChild() != null)){
                    it = it.getRightChild();
                }
                else if((newNode.compareTo(it) == 1) && (it.getRightChild() == null)){      //if newNode > it
                    newNode.addParent(it);
                    it.addRightChild(newNode);
                }
            }
        }
        logger.info("Node successfully added !");
    }

    public String toString(){
        logger.warn("Preparing for printing Tree..");
        treeToString(root);
        return treeString;
    }

    private void treeToString(TreeNode node){
        if (node.getLeftChild() != null){
            treeToString(node.getLeftChild());
        }
        treeString += node.getData() + "\n";
        if (node.getRightChild() != null){
            treeToString(node.getRightChild());
        }
    }
    /*
    private void treeSerial(ObjectOutputStream oos, TreeNode node) throws IOException{
        if (node.getLeftChild() != null){
            oos.writeObject("\n<leftChild>\n");
            treeSerial(oos, node.getLeftChild());
            oos.writeObject("\n</leftChild>\n");
        }
        if (node.getRightChild() != null){
            oos.writeObject("\n<rightChild>\n");
            treeSerial(oos,node.getRightChild());
            oos.writeObject("\n</rightChild>\n");
        }
        oos.writeObject(node);
    } */

    private void writeObject(ObjectOutputStream oos) throws IOException{
        logger.warn("Preparing to serialization..");
        oos.defaultWriteObject();
        logger.info("Tree successfully serialized !");
        /*oos.writeObject("\n<?xml version=\"1.0\">\n");
        oos.writeObject("<object class=\"by.home.app.Tree\">\n");
        oos.writeObject("<root>\n");
        treeSerial(oos, root);
        oos.writeObject("\n</root>\n");
        oos.writeObject("</object>");*/
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
        logger.warn("Preparing to deserialization..");
        ois.defaultReadObject();
        logger.info("Tree successfully deserialized !");
    }

    public class TreeNode implements Serializable,Comparable<TreeNode>{
        public int key;
        private UserData data;
        private TreeNode leftChild;
        private TreeNode rightChild;
        private TreeNode parent;

        public TreeNode(UserData data){
            this.data = data;
            this.key = data.hashCode();
        }

        public void addLeftChild(TreeNode leftChild){
            this.leftChild = leftChild;
        }
        public void addRightChild(TreeNode rightChild){
            this.rightChild = rightChild;
        }
        public void addParent(TreeNode parent){
            this.parent = parent;
        }
        public void setData(UserData data){
            this.data = data;
            this.key = data.hashCode();
        }

        public TreeNode getLeftChild(){
            return leftChild;
        }
        public TreeNode getRightChild(){
            return rightChild;
        }
        public TreeNode getParent(){
            return parent;
        }
        public UserData getData(){
            return data;
        }

        @Override
        public int compareTo(TreeNode tn1){
            if (this.key > tn1.key){
                return 1;
            }
            else return -1;
        }
    }

}


